package config

import (
	"reflect"
)

type IConfigDefault interface {
	ToDefault(body IConfigDefault)
}

type RendererDefault struct {
	sort int
}

func NewRendererDefault(sort int) *RendererDefault {
	return &RendererDefault{
		sort: sort,
	}
}

func (r *RendererDefault) Name() string {
	return "default"
}

func (r *RendererDefault) Sort() int {
	return r.sort
}

func (r *RendererDefault) Render(body reflect.Value, desc *ConfigDesc) error {
	if ic, ok := body.Interface().(IConfigDefault); ok {
		ic.ToDefault(ic)
	}

	rv := body
	if rv.Kind() == reflect.Ptr {
		rv = rv.Elem()
	}
	for fieldName, child := range desc.Children {
		rvf := findFieldWithLowerName(rv, fieldName)
		if !rvf.IsValid() {
			continue
		}

		if rvf.IsNil() {
			rvf.Set(reflect.New(rvf.Type().Elem()))
		}

		if err := r.Render(rvf, child); err != nil {
			return err
		}
	}
	for fieldName, childMap := range desc.ChildrenMap {
		rvf := findFieldWithLowerName(rv, fieldName)
		if !rvf.IsValid() {
			continue
		}
		if rvf.IsNil() {
			rvf.Set(reflect.MakeMapWithSize(rvf.Type(), 4))
		}

		for childName, child := range childMap {
			if !rvf.MapIndex(reflect.ValueOf(childName)).IsValid() {
				rvf.SetMapIndex(reflect.ValueOf(childName), reflect.New(child.Type))
			}
			sub := rvf.MapIndex(reflect.ValueOf(childName))
			if err := r.Render(sub, child); err != nil {
				return err
			}
		}
	}

	return nil
}
